from abc import ABC, abstractmethod
from typing import List


# -------------------------- 1. 产品（Product）：文档 --------------------------
class Document:
    def __init__(self):
        self.title = ""          # 必选：标题
        self.content = ""        # 必选：正文
        self.images = []         # 可选：图片列表（每个元素为{"url": "...", "alt": "..."}）
        self.attachments = []    # 可选：附件列表（每个元素为{"name": "...", "path": "..."}）

    def __str__(self):
        """输出文档内容（根据类型自动格式化）"""
        if hasattr(self, "type"):
            if self.type == "markdown":
                return self._to_markdown()
            elif self.type == "html":
                return self._to_html()
        return f"标题：{self.title}\n正文：{self.content}\n图片：{self.images}\n附件：{self.attachments}"

    def _to_markdown(self):
        """转换为Markdown格式"""
        md = [f"# {self.title}", "\n", self.content]
        # 添加图片
        for img in self.images:
            md.append(f"\n![{img['alt']}]({img['url']})")
        # 添加附件
        for attach in self.attachments:
            md.append(f"\n[{attach['name']}]({attach['path']})")
        return "".join(md)

    def _to_html(self):
        """转换为HTML格式"""
        html = [f"<h1>{self.title}</h1>", f"<p>{self.content}</p>"]
        # 添加图片
        for img in self.images:
            html.append(f'<img src="{img["url"]}" alt="{img["alt"]}">')
        # 添加附件
        for attach in self.attachments:
            html.append(f'<a href="{attach["path"]}">{attach["name"]}</a>')
        return "\n".join(html)


# -------------------------- 2. 抽象建造者（Builder） --------------------------
class DocumentBuilder(ABC):
    @abstractmethod
    def set_title(self, title: str) -> None:
        """设置标题（必选）"""
        pass

    @abstractmethod
    def set_content(self, content: str) -> None:
        """设置正文（必选）"""
        pass

    @abstractmethod
    def add_image(self, url: str, alt: str) -> None:
        """添加图片（可选）"""
        pass

    @abstractmethod
    def add_attachment(self, name: str, path: str) -> None:
        """添加附件（可选）"""
        pass

    @abstractmethod
    def get_document(self) -> Document:
        """获取构建完成的文档"""
        pass


# -------------------------- 3. 具体建造者（ConcreteBuilder） --------------------------
class MarkdownDocumentBuilder(DocumentBuilder):
    def __init__(self):
        self.document = Document()
        self.document.type = "markdown"  # 标记文档类型

    def set_title(self, title: str) -> None:
        self.document.title = title

    def set_content(self, content: str) -> None:
        self.document.content = content

    def add_image(self, url: str, alt: str) -> None:
        self.document.images.append({"url": url, "alt": alt})

    def add_attachment(self, name: str, path: str) -> None:
        self.document.attachments.append({"name": name, "path": path})

    def get_document(self) -> Document:
        # 校验必选组件
        if not self.document.title or not self.document.content:
            raise ValueError("Markdown文档必须包含标题和正文")
        return self.document


class HtmlDocumentBuilder(DocumentBuilder):
    def __init__(self):
        self.document = Document()
        self.document.type = "html"  # 标记文档类型

    def set_title(self, title: str) -> None:
        self.document.title = title

    def set_content(self, content: str) -> None:
        self.document.content = content

    def add_image(self, url: str, alt: str) -> None:
        self.document.images.append({"url": url, "alt": alt})

    def add_attachment(self, name: str, path: str) -> None:
        self.document.attachments.append({"name": name, "path": path})

    def get_document(self) -> Document:
        if not self.document.title or not self.document.content:
            raise ValueError("HTML文档必须包含标题和正文")
        return self.document


# -------------------------- 4. 指挥者（Director）：控制构建流程 --------------------------
class DocumentDirector:
    def __init__(self, builder: DocumentBuilder):
        self.builder = builder

    def build_simple_document(self, title: str, content: str) -> Document:
        """构建简单文档（仅标题+正文）"""
        self.builder.set_title(title)
        self.builder.set_content(content)
        return self.builder.get_document()

    def build_complete_document(self, title: str, content: str, images: List[dict], attachments: List[dict]) -> Document:
        """构建完整文档（标题+正文+图片+附件）"""
        self.builder.set_title(title)
        self.builder.set_content(content)
        # 添加图片
        for img in images:
            self.builder.add_image(img["url"], img["alt"])
        # 添加附件
        for attach in attachments:
            self.builder.add_attachment(attach["name"], attach["path"])
        return self.builder.get_document()


# -------------------------- 5. 客户端使用 --------------------------
if __name__ == "__main__":
    # 场景1：生成Markdown简单文档
    md_builder = MarkdownDocumentBuilder()
    md_director = DocumentDirector(md_builder)
    simple_md = md_director.build_simple_document(
        title="Python建造者模式",
        content="建造者模式可以灵活构建复杂对象，分离构建过程与表示。"
    )
    print("=== Markdown简单文档 ===")
    print(simple_md)

    # 场景2：生成HTML完整文档
    html_builder = HtmlDocumentBuilder()
    html_director = DocumentDirector(html_builder)
    complete_html = html_director.build_complete_document(
        title="HTML文档示例",
        content="这是一个包含图片和附件的完整HTML文档。",
        images=[{"url": "https://example.com/img1.jpg", "alt": "示例图片1"}],
        attachments=[{"name": "文档附件.pdf", "path": "/docs/attach1.pdf"}]
    )
    print("\n=== HTML完整文档 ===")
    print(complete_html)